#coding: utf8
'''
==================================================================================
Created on 2020-10-26
Author: Simon
==================================================================================
'''
from src.libs.database import Database 
from src.common.base import Project, Module
from src.libs.log import L

def create_project(create_user, name, description=""):
    p = Project(None, name, create_user, description)
    flag = p.create()
    if flag != -1:
        for m in ["测试", "运维", "其它"]:
            t = Module(flag, None, m, create_user)
            t.create()
        
    return flag if flag != -1 else False

def get_project_list(create_user, category, department, page = 0, size = 26):
    db = Database()
    keys = ['id', 'name', 'createUser', 'status', 'manager', 'createTime', 'description',
            'category', 'department', 'mark']
    sql, params = "select " + ','.join(keys) + " from project where 1", []
    if create_user != '': 
        sql += " and createUser=%s"
        params.append(create_user)
    if category != '': 
        sql += " and category=%s"
        params.append(category)
    if department != '': 
        sql += " and department=%s"
    sql += " order by createTime desc"
    data = []
    count, cursor = db.selectPage(sql, params, page, size)
    for item in cursor:            
        line = { k:item[i] for (i, k) in enumerate(keys) }
        line['createTime'] = str(line['createTime'])
        data.append(line)
                
    return {'count': count, 'lines': data}


'''
    集成项目和模块的各种操作
    pre：用于修改时表示修改前的值；
        用于合并时表示合并到的目标id
'''
def manage_pm(key, p_id, m_id, t_id, name, pre, user):
    conf = {'projOpen': ['project', 'status', 0, p_id, 'projectId'], 
            'projClose': ['project', 'status', 1, p_id, 'projectId'], 
            'projFinish': ['project', 'status', 2, p_id, 'projectId'], 
            'modOpen': ['module', 'status', 0, m_id, 'moduleId'], 
            'modClose': ['module', 'status', 1, m_id, 'moduleId'], 
            'modFinish': ['module', 'status', 2, m_id, 'moduleId'],
            'projRename': ['project', 'name', name, p_id, 'projectId'], 
            'modRename': ['module', 'name', name, m_id, 'moduleId'],
            'projMerge': ['project', name, pre, p_id, 'projectId'],
            'modMerge': ['module', name, pre, m_id, 'moduleId'],
            'taskMove': ['task', m_id, pre, t_id, 'moduleId'],
            'modMove': ['module', p_id, pre, m_id, 'projectId']
    }
    if key not in conf: return -1, "无效操作"
    table, field, value, _id, field2 = conf[key]
    
    if key == 'modMove': return move_module(m_id, p_id, value, user)
    if key == 'taskMove': return move_task(t_id, m_id, value, user)
    if key == 'projMerge' or key == 'modMerge': return merge_pm(table, _id, value, user) 
    
    db = Database()
    '''操作日志'''
    sql1 = "insert into operation (user, category, cid, src, dest, description) \
        values (%s, %s, %s, %s, %s, %s)" 
    param1 = (user, key, _id, pre, value, "change %s %s" % (table, field))
    params = (value, _id)
    sqls = [["update {} set {} = %s where id=%s".format(table, field), params], [sql1, param1]]
    if field == 'name':
        sql2 = "update record_day set {}=%s where {}=%s".format(table, field2)
        sql3 = "update record_day_del set {}=%s where {}=%s".format(table, field2)
        sql4 = "update plan_day set {}=%s where {}=%s".format(table, field2)
        sqls += [[sql2, params], [sql3, params], [sql4, params]]
    '''End If'''
    
    flag, _ = db.Transaction(sqls)
    return flag, "操作失败"


def merge_pm(table, _id, _id2, user):
    if table == 'project':
        flag, msg = merge_project(None, _id, _id2, user)
    elif table == 'module':
        flag, msg = merge_module(None, _id, _id2, user)
    if not flag: return flag, msg
    return flag, "合并成功"
    
'''
合并项目：
    1.将module表中的projectId替换
    2.相关模块任务处理：同名模块则执行合并逻辑，不同名模块直接修改从属关系即可。
'''
def merge_project(db, p_id, p_id2, user):
    if not db: db = Database()
    sql = '''select m.id id, m.name mName, ct, b.id id2, p.name pName, b.pn pName2 from module m 
        left join (select name, count(1) ct from module where projectId in (%s, %s) group by name) a
        on m.name=a.name left join (select m1.id id, m1.name name, p1.name pn from module m1 
            left join project p1 on projectId=p1.id where projectId=%s
        ) b on m.name=b.name 
        left join project p on projectId=p.id
        where projectId=%s
    '''
    res = db.read_all(sql, (p_id, p_id2, p_id2, p_id))
    sqls, ids = [], []
    desp, p_name, p_name2 = "", None, None
    for item in res:
        _id, count, id2, name = item['id'], item['ct'], item['id2'], item['mName']
        desp += "%s_%s_%s|" % (_id, name, count) 
        if p_name == None and item['pName'] != None: p_name = item['pName']
        if p_name2 == None and item['pName2'] != None: p_name2 = item['pName2']
        
        if count > 1:
            sqls += merge_module(db, _id, id2, user, False)
        else:
            ids.append(_id)
        '''End If'''
    '''End For'''
    
    params, txt = [p_id2] + ids, ','.join(['%s' for i in ids])
    sql1 = "update module set projectId=%s where id in ({})".format(txt)
    sql2 = "update task set projectId=%s where moduleId in ({})".format(txt)
    sql3 = 'update record_day set projectId=%s, project=%s, mark=%s where moduleId in ({})'.format(txt)
    sql4 = 'update record_day_del set projectId=%s, project=%s, mark=%s where moduleId in ({})'.format(txt)
    sql5 = 'update plan_day set projectId=%s, project=%s, mark=%s where moduleId in ({})'.format(txt)
    sql6 = "update project set status=-1 where id=%s"
    sql7 = "insert into operation (user, category, cid, src, dest, description) values (%s, %s, %s, %s, %s, %s)"
    params3, params6 = [p_id2, p_name2, "p%s" % p_id] + ids, [p_id]
    params7 = [user, "projMerge", p_id, p_name, p_id2, desp]
    
    '''存在需要直接迁移的模块'''
    if len(ids) > 0: sqls += [[sql1, params], [sql2, params], [sql3, params3], [sql4, params3], [sql5, params3]]
    sqls += [[sql6, params6], [sql7, params7]]
    flag, _ = db.Transaction(sqls)
    
    return flag, "合并失败"
    

'''
合并模块：
    1.合并任务（不含同名任务）
    2.删除原模块（更改所属项目，逻辑删除）
把模块m_id合并到m_id2去
'''
def merge_module(db, m_id, m_id2, user, auto_run=True):
    if not db: db = Database()
    '''有同名任务的模块无法合并，涉及到复杂的进度控制逻辑，仅支持先处理完同名情况再合并'''
    if check_same_task(db, m_id, m_id2): return False, "两模块中含有同名任务，请处理后再合并！"
    
    sql = '''SELECT p.id pId, p.name pName, m.id mId, m.name mName FROM module m 
        left join project p on m.projectId=p.id where m.id in (%s, %s)'''
    info = db.read_all(sql, [m_id, m_id2])
    if len(info) != 2: return False, "模块信息查询错误！"
    
    i = 0 if info[0]['mId'] == int(m_id2) else 1 
    m1, m2 = info[i-1], info[i]
    
    '''记录原项目和模块ID'''
    p_id, p_id2 = info[i-1]['pId'], info[i]['pId']
    mark = "p%s-m%s" % (p_id, m_id)
    params = (p_id2, m2['pName'], m2['mId'], m2['mName'], mark, m_id)
    sql1 = 'update record_day set projectId=%s, project=%s, moduleId=%s, module=%s, mark=%s where moduleId=%s'
    sql2 = 'update record_day_del set projectId=%s, project=%s, moduleId=%s, module=%s, mark=%s where moduleId=%s'
    sql3 = 'update plan_day set projectId=%s, project=%s, moduleId=%s, module=%s, mark=%s where moduleId=%s'
    sql4 = 'delete from module where id=%s'
    sql5 = 'update task set projectId=%s, moduleId=%s, mark=%s where moduleId=%s'
    sql6 = '''insert into operation (user, category, cid, src, dest, description)
        values (%s, %s, %s, %s, %s, %s)'''
    opt = (user, "modMerge", m_id, p_id, p_id2, "_".join([mark, m1['pName'], m1['mName']]))
    sqls = [[sql1, params], [sql2, params], [sql3, params], [sql4, [m_id]], [sql5, (p_id2, m_id2, mark, m_id)], 
            [sql6, opt]]
    
    if not auto_run: return sqls
    
    flag, _ = db.Transaction(sqls)
    return flag, "合并失败"


'''移动模块前，获取同名模块信息及相关项目信息'''
def pre_module_task(db, m_id, p_id, p_id2):
    if not db: db = Database()
    sql = '''select id, name, "mod" from module where projectId=%s and name=(select name from module where id=%s)
        union select id, name, "proj" from project where id in (%s, %s)'''
    info = db.read_all(sql, [p_id2, m_id, p_id, p_id2])
    mod, p1, p2 = None, None, None
    for item in info:
        if item['mod'] == "proj":
            if item['id'] == int(p_id): p1 = item
            if item['id'] == int(p_id2): p2 = item
        else:
            mod = item
        '''End If'''
    '''End For'''
    return mod, p1, p2

'''迁移模块'''
def move_module(m_id, p_id, p_id2, user):
    db = Database()
    mod, p1, p2 = pre_module_task(db, m_id, p_id, p_id2)
    '''检查目标模块下是否有同名任务'''
    if mod: return merge_module(db, m_id, mod['name'], user)
    
    mark = "p%s-p%s" % (p_id, p_id2)
    params = (p2['id'], p2['name'], mark, m_id)
    sql1 = 'update record_day set projectId=%s, project=%s, mark=%s where moduleId=%s'
    sql2 = 'update record_day_del set projectId=%s, project=%s, mark=%s where moduleId=%s'
    sql3 = 'update plan_day set projectId=%s, project=%s, mark=%s where moduleId=%s'
    sql4, params4 = 'update module set projectId=%s, mark=%s where id=%s', (p_id2, mark, m_id)
    sql5 = '''insert into operation (user, category, cid, src, dest, description)
        values (%s, %s, %s, %s, %s, %s)'''
    opt = (user, "modMove", m_id, p_id, p_id2, "_".join([mark, p1['name']]))
    sqls = [[sql1, params], [sql2, params], [sql3, params], [sql4, params4], [sql5, opt]]
    
    flag, _ = db.Transaction(sqls)
    return flag, "迁移失败"
    

'''移动任务前，获取同名任务信息及相关模块信息'''
def pre_move_task(db, t_id, m_id, m_id2):
    if not db: db = Database()
    sql = '''select id, name, "task" from task where moduleId=%s and name=(select name from task where id=%s)
        union select id, name, "module" from module where id in (%s, %s)'''
    info = db.read_all(sql, [m_id2, t_id, m_id, m_id2])
    task, m1, m2 = None, None, None
    for item in info:
        if item['task'] == "module":
            if item['id'] == int(m_id): m1 = item
            if item['id'] == int(m_id2): m2 = item
        else:
            task = item
        '''End If'''
    '''End For'''
    return task, m1, m2

def move_task(t_id, m_id, m_id2, user):
    db = Database()
    task, m1, m2 = pre_move_task(db, t_id, m_id, m_id2)

    mark = "m%s" % (m_id)
    params = (m2['id'], m2['name'], task['id'] if task else t_id, mark, t_id)
    sql1 = 'update record_day set moduleId=%s, module=%s, taskId=%s, mark=%s where taskId=%s'
    sql2 = 'update record_day_del set moduleId=%s, module=%s, taskId=%s, mark=%s where taskId=%s'
    sql3 = 'update plan_day set moduleId=%s, module=%s, taskId=%s, mark=%s where taskId=%s'
    sql4, params4 = 'delete from task where id=%s', [t_id]
    sql5, params5 = 'update task set moduleId=%s, mark=%s where id=%s', (m_id2, mark, t_id)
    sql6 = '''insert into operation (user, category, cid, src, dest, description)
        values (%s, %s, %s, %s, %s, %s)'''
    opt = (user, "taskMove", t_id, m_id, m_id2, "_".join([mark, m1['name']]))
    sqls = [[sql1, params], [sql2, params], [sql3, params], [sql6, opt]]
    '''检查目标模块下是否有同名任务'''
    if task:
        sqls += [[sql4, params4]]
    else:
        sqls += [[sql5, params5]]
    '''End If'''
    
    flag, _ = db.Transaction(sqls)
    return flag, "迁移失败"
    
    

''' TODO：暂不考虑非正式任务的重名情况，即record_day中任务未在任务表创建，本系统逻辑似乎兼容该种情况 '''
def check_same_task(db, m_id, m_id2):
    if not db: db = Database()
    sql = '''select count(1) count from (select name, count(1) ct from task where moduleId in (%s, %s) 
        group by name HAVING ct > 1) a'''
    info = db.read_one(sql, (m_id, m_id2))
    if int(info['count']) > 0: return True
    
    return False



if __name__ == '__main__':
    # create_project("lucy", "p1", "mp number")
    # merge_pm()
    # merge_module()
    # merge_module(None, 17, 18)
    merge_project(None, 44, 48, "admin")
    
    # merge_module(None, 23, 24)
    
    # check_same_task(None, 58, 96)
    
#     ps = get_project_list("", "", "")
#     print(ps)

        
    pass